﻿using Newtonsoft.Json;
using RestSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SyntacticSugar;
using SPW.Infrastructure.Interfaces;
using SPW.Infrastructure.Models;

namespace SPW.Infrastructure.Utils
{
    /// <summary>
    /// 简单的请求客户端
    /// </summary>
    public class SimpleRequestClient : IDataServiceClient
    {
        private readonly string _hostAddress = "";
        private readonly RestClient client;
        private bool _isDebug = false;

        /// <summary>
        /// 访问token
        /// </summary>
        public string AccessToken { get; private set; }
        /// <summary>
        /// 刷新token
        /// </summary>
        public string RefreshId { get; private set; }
        /// <summary>
        /// 用户id
        /// </summary>
        public string UserId { get; private set; }
        /// <summary>
        /// 用户昵称
        /// </summary>
        public string NickName { get; private set; }

        public SimpleRequestClient(string hostAddress)
        {
            _hostAddress = hostAddress;
            client = new RestClient(_hostAddress);
        }

        private bool ResultCodeWith(ResultDataModel resultData, Action<Task<bool>> action = null)
        {
            bool isSuccess = true;

            switch (resultData.Code)
            {
                case ResultCodes.Exception:
                    {
                        string errorMsg = "";
                        if (_isDebug)
                        {
                            errorMsg = resultData.Message;
                        }
                        throw new Exception($"服务器发生异常，请与管理员联系！{errorMsg}");
                    }
                case ResultCodes.UnLogin:
                    {
                        if (RefreshId.IsValuable() && action.IsValuable())
                        {
                            RefreshAsync(RefreshId).ContinueWith(action);
                        }
                        else
                        {
                            throw new Exception(resultData.Message);
                        }
                    }
                    break;
                case ResultCodes.UnAuthorized:
                    {
                        throw new Exception(resultData.Message);
                    }
            }

            return isSuccess;
        }

        /// <summary>
        /// 设置调试状态
        /// </summary>
        /// <param name="success"></param>
        public void SetDebugState(bool success)
        {
            _isDebug = success;
        }

        /// <summary>
        /// 设置token
        /// </summary>
        /// <param name="access_token"></param>
        public void SetToken(string access_token)
        {
            AccessToken = access_token;
            client.RemoveDefaultParameter("access_token");//移除旧的
            client.AddDefaultHeader("access_token", AccessToken);
        }

        #region Async
        /// <summary>
        /// 认证
        /// </summary>
        /// <param name="username"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public Task<bool> AuthenticatorAsync(string username, string password)
        {
            password = SyntacticSugar.EncryptSugar.GetInstance().MD5(password);
            var request = new RestRequest("/oauth2/token");
            request.AddParameter("grant_type", "password");
            request.AddParameter("remember", true);
            request.AddParameter("username", username);
            request.AddParameter("password", password);

            return client.PostAsync<AuthorizedResultDataModel>(request)
                 .ContinueWith<bool>(t =>
                 {
                     bool success = false;
                     if (t.IsCompleted && t.Exception.IsNullOrEmpty())
                     {
                         var result = t.Result;

                         if (result.Code != ResultCodes.Complete)
                         {
                             throw new Exception(result.Message);
                         }

                         //更新数据
                         SetToken(result.AccessToken);
                         RefreshId = result.RefreshToken;
                         UserId = result.Id;
                         NickName = result.NickName;
                         success = true;
                     }
                     else
                     {
                         throw t.Exception ?? new Exception("认证失败");
                     }
                     return success;
                 });
        }

        /// <summary>
        /// 刷新认证
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Task<bool> RefreshAsync(string id)
        {
            var request = new RestRequest("/oauth2/token");
            request.AddParameter("grant_type", "refresh_token");
            request.AddParameter("remember", true);
            request.AddParameter("refresh_token", id);

            return client.PostAsync<AuthorizedResultDataModel>(request)
                .ContinueWith<bool>(t =>
                {
                    bool success = false;

                    if (t.IsCompleted && t.Exception.IsNullOrEmpty())
                    {
                        var result = t.Result;

                        if (result.Code != ResultCodes.Complete)
                        {
                            throw new Exception(result.Message);
                        }

                        //更新数据
                        SetToken(result.AccessToken);
                        RefreshId = result.RefreshToken;
                        success = true;
                    }
                    else
                    {
                        throw t.Exception ?? new Exception("刷新token失败");
                    }
                    return success;
                });
        }

        public Task<ResultDataModel> HttpGetAsync(string urlPathString, Dictionary<string, string> datas = null)
        {
            var request = new RestRequest(urlPathString);
            //创建参数
            if (datas.IsValuable())
            {
                datas.TryForEach(d => request.AddParameter(d.Key, d.Value));
            }

            return client.GetAsync<ResultDataModel>(request)
                .ContinueWith(t =>
                {
                    if (t.IsCompleted && t.Exception.IsNullOrEmpty())
                    {
                        var result = t.Result;

                        var nTask = CheckIsLogIn(result, t);
                        nTask.Wait();

                        return nTask.Result;
                    }
                    else
                    {
                        throw t.Exception ?? new Exception($"Get Error：{urlPathString}");
                    }
                });
        }

        private Task<TResult> CheckIsLogIn<TResult>(ResultDataModel result, Task<TResult> originalTask)
        {
            if (result.Code == ResultCodes.UnLogin)
            {
                return RefreshAsync(RefreshId).ContinueWith<TResult>(r =>
                {
                    if (r.Result)
                    {
                        originalTask.Wait();
                        return originalTask.Result;
                    }
                    return default(TResult);
                });
            }
            return originalTask;
        }

        /// <summary>
        /// HttpGet
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="urlPathString"></param>
        /// <param name="datas"></param>
        /// <returns></returns>
        public Task<TResult> HttpGetAsync<TResult>(string urlPathString, Dictionary<string, string> datas = null) where TResult : class, new()
        {
            var request = new RestRequest(urlPathString);
            //创建参数
            if (datas.IsValuable())
            {
                datas.TryForEach(d => request.AddParameter(d.Key, d.Value));
            }

            return client.GetAsync<ResultDataModel<TResult>>(request)
                .ContinueWith<TResult>(t =>
                {
                    if (t.IsCompleted && t.Exception.IsNullOrEmpty())
                    {
                        var result = t.Result;

                        var nTask = CheckIsLogIn(result, t);
                        nTask.Wait();

                        return nTask.Result.Data;
                    }
                    else
                    {
                        throw t.Exception ?? new Exception($"Get Error：{urlPathString}");
                    }
                });
        }

        public Task<ResultDataModel> HttpPostAsync(string urlPathString, Dictionary<string, string> datas)
        {
            var request = new RestRequest(urlPathString);
            //创建参数
            datas.TryForEach(d => request.AddParameter(d.Key, d.Value));

            return client.PostAsync<ResultDataModel>(request)
                .ContinueWith<ResultDataModel>(t =>
            {
                if (t.IsCompleted && t.Exception.IsNullOrEmpty())
                {
                    var result = t.Result;

                    var nTask = CheckIsLogIn(result, t);
                    nTask.Wait();

                    return nTask.Result;
                }
                else
                {
                    throw t.Exception ?? new Exception($"Post Error：{urlPathString}");
                }
            });
        }

        public Task<ResultDataModel> HttpPostAsync(string urlPathString, object datas)
        {
            var request = new RestRequest(urlPathString);
            //创建参数
            request.AddJsonBody(datas);

            return client.PostAsync<ResultDataModel>(request)
                .ContinueWith<ResultDataModel>(t =>
                {
                    if (t.IsCompleted && t.Exception.IsNullOrEmpty())
                    {
                        var result = t.Result;

                        var nTask = CheckIsLogIn(result, t);
                        nTask.Wait();

                        return nTask.Result;
                    }
                    else
                    {
                        throw t.Exception ?? new Exception($"Post Error：{urlPathString}");
                    }
                });
        }

        public Task<TResult> HttpPostAsync<TResult>(string urlPathString, Dictionary<string, string> datas) where TResult : class, new()
        {
            var request = new RestRequest(urlPathString);
            //创建参数
            datas.TryForEach(d => request.AddParameter(d.Key, d.Value));

            return client.PostAsync<ResultDataModel<TResult>>(request)
                .ContinueWith<TResult>(t =>
                {
                    if (t.IsCompleted && t.Exception.IsNullOrEmpty())
                    {
                        var result = t.Result;

                        var nTask = CheckIsLogIn(result, t);
                        nTask.Wait();

                        return nTask.Result.Data;
                    }
                    else
                    {
                        throw t.Exception ?? new Exception($"Post Error：{urlPathString}");
                    }
                });
        }

        public Task<TResult> HttpPostAsync<TResult>(string urlPathString, object datas) where TResult : class, new()
        {
            var request = new RestRequest(urlPathString);
            //创建参数
            request.AddJsonBody(datas);

            return client.PostAsync<ResultDataModel<TResult>>(request)
                .ContinueWith<TResult>(t =>
                {
                    if (t.IsCompleted && t.Exception.IsNullOrEmpty())
                    {
                        var result = t.Result;

                        var nTask = CheckIsLogIn(result, t);
                        nTask.Wait();

                        return nTask.Result.Data;
                    }
                    else
                    {
                        throw t.Exception ?? new Exception($"Post Error：{urlPathString}");
                    }
                });
        }

        public Task<ResultDataModel> HttpPutAsync(string urlPathString, string id, Dictionary<string, string> datas)
        {
            var request = new RestRequest(urlPathString + "/{id}");
            request.AddUrlSegment("id", id);
            //创建参数
            datas.TryForEach(d => request.AddParameter(d.Key, d.Value));

            return client.PutAsync<ResultDataModel>(request)
                .ContinueWith<ResultDataModel>(t =>
                {
                    if (t.IsCompleted && t.Exception.IsNullOrEmpty())
                    {
                        var result = t.Result;

                        var nTask = CheckIsLogIn(result, t);
                        nTask.Wait();

                        return nTask.Result;
                    }
                    else
                    {
                        throw t.Exception ?? new Exception($"Put Error：{urlPathString}");
                    }
                });
        }

        public Task<TResult> HttpPutAsync<TResult>(string urlPathString, string id, Dictionary<string, string> datas) where TResult : class, new()
        {
            var request = new RestRequest(urlPathString + "/{id}");
            request.AddUrlSegment("id", id);
            //创建参数
            datas.TryForEach(d => request.AddParameter(d.Key, d.Value));

            return client.PutAsync<ResultDataModel<TResult>>(request)
                .ContinueWith<TResult>(t =>
                {
                    if (t.IsCompleted && t.Exception.IsNullOrEmpty())
                    {
                        var result = t.Result;

                        var nTask = CheckIsLogIn(result, t);
                        nTask.Wait();

                        return nTask.Result.Data;
                    }
                    else
                    {
                        throw t.Exception ?? new Exception($"Put Error：{urlPathString}");
                    }
                });
        }

        public Task<ResultDataModel> HttpPutAsync(string urlPathString, string id, object datas)
        {
            var request = new RestRequest(urlPathString + "/{id}");
            request.AddUrlSegment("id", id);
            //创建参数
            request.AddJsonBody(datas);

            return client.PutAsync<ResultDataModel>(request)
                .ContinueWith<ResultDataModel>(t =>
                {
                    if (t.IsCompleted && t.Exception.IsNullOrEmpty())
                    {
                        var result = t.Result;

                        var nTask = CheckIsLogIn(result, t);
                        nTask.Wait();

                        return nTask.Result;
                    }
                    else
                    {
                        throw t.Exception ?? new Exception($"Put Error：{urlPathString}");
                    }
                });
        }

        public Task<TResult> HttpPutAsync<TResult>(string urlPathString, string id, object datas) where TResult : class, new()
        {
            var request = new RestRequest(urlPathString + "/{id}");
            request.AddUrlSegment("id", id);
            //创建参数
            request.AddJsonBody(datas);

            return client.PutAsync<ResultDataModel<TResult>>(request)
                .ContinueWith<TResult>(t =>
                {
                    if (t.IsCompleted && t.Exception.IsNullOrEmpty())
                    {
                        var result = t.Result;

                        var nTask = CheckIsLogIn(result, t);
                        nTask.Wait();

                        return nTask.Result.Data;
                    }
                    else
                    {
                        throw t.Exception ?? new Exception($"Put Error：{urlPathString}");
                    }
                });
        }

        public Task<ResultDataModel> HttpDeleteAsync(string urlPathString, string id)
        {
            var request = new RestRequest(urlPathString + "/{id}");
            request.AddUrlSegment("id", id);

            return client.DeleteAsync<ResultDataModel>(request)
                .ContinueWith<ResultDataModel>(t =>
                {
                    if (t.IsCompleted && t.Exception.IsNullOrEmpty())
                    {
                        var result = t.Result;

                        var nTask = CheckIsLogIn(result, t);
                        nTask.Wait();

                        return nTask.Result;
                    }
                    else
                    {
                        throw t.Exception ?? new Exception($"Put Error：{urlPathString}");
                    }
                });
        }

        public Task<TResult> HttpDeleteAsync<TResult>(string urlPathString, string id) where TResult : class, new()
        {
            var request = new RestRequest(urlPathString + "/{id}");
            request.AddUrlSegment("id", id);

            return client.DeleteAsync<ResultDataModel<TResult>>(request)
                .ContinueWith<TResult>(t =>
                {
                    if (t.IsCompleted && t.Exception.IsNullOrEmpty())
                    {
                        var result = t.Result;

                        var nTask = CheckIsLogIn(result, t);
                        nTask.Wait();

                        return nTask.Result.Data;
                    }
                    else
                    {
                        throw t.Exception ?? new Exception($"Delete Error：{urlPathString}");
                    }
                });
        }
        #endregion
    }
}
